
#include "board.h"
#include "stdio.h"
#include "at_device_m5311.h"

#define DBG_TAG                     "nb"
#ifdef RT_M5311_DEBUG
#define DBG_LVL                     DBG_LOG
#else
#define DBG_LVL                     DBG_INFO
#endif
#include <rtdbg.h>

#ifdef BSP_USING_M5311 /* BSP_USING_M5311 */

static uint8_t m5311_dat[RT_M5311_RECV_SIZE] = {0};
static struct rt_nb_device m5311 = 
{
  .nb_msg.dat = m5311_dat,
};
static rt_mutex_t m5311_mt = RT_NULL;
static rt_event_t m5311_evt = RT_NULL;

static void urc_conn_func(struct at_client *client, const char *data, rt_size_t size);
static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size);
static void urc_net_status_func(struct at_client *client, const char *data, rt_size_t size);
static void urc_device_status_func(struct at_client *client, const char *data, rt_size_t size);

static struct at_urc m5311_urc_table[] = {
{"+CSCON:", "\r\n", urc_conn_func},
{"+CEREG:","\r\n", urc_net_status_func},
{"+MLWEVTIND:","\r\n", urc_device_status_func},
{"+MLWREAD:", "\r\n", urc_recv_func},
};

static void hextostring(uint8_t * dst, uint8_t * src, uint16_t len)
{
  uint16_t i = 0;
  for(;i < len;i ++)
    rt_sprintf((char *)&dst[2*i], "%02x", src[i]);
}

static void stringtohex(uint8_t * dst, uint8_t * src, uint16_t len)
{
  uint16_t i = 0;
  int temp = 0;
  
  for(;i < len;i ++)
  {
    sscanf((char *)&src[2*i],"%02x",&temp);
    dst[i] = temp;
//    dst[i] = src[2*i] * 16 + src[2*i + 1];
  }
}

static void urc_conn_func(struct at_client *client, const char *data, rt_size_t size)
{
  if(rt_strstr(data,"+CSCON:1") != RT_NULL)
    m5311.info.sign_mode = 1;
  else
    m5311.info.sign_mode = 0;
  LOG_D("%s",data);
}

static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)
{
  int len = 0;
  
  LOG_D("%s",data);
  sscanf(data,"+MLWREAD:%d,",&len);
  if(len > RT_M5311_RECV_SIZE)
    len = RT_M5311_RECV_SIZE;
  if(rt_strstr(data,",") != RT_NULL)
    stringtohex(m5311.nb_msg.dat, (uint8_t *)(rt_strstr(data,",") + 1), len);
  m5311.nb_msg.len = len;
#ifdef RT_USING_ULOG
  LOG_HEX("nb_recv", 20, m5311.nb_msg.dat, m5311.nb_msg.len);
#endif
  
  if(m5311.parent.rx_indicate != RT_NULL) //������������ģ���ж�
    m5311.parent.rx_indicate(&m5311.parent, m5311.nb_msg.len);
}

static void urc_net_status_func(struct at_client *client, const char *data, rt_size_t size)
{
  LOG_D("%s",data);
  if(rt_strstr(data,"+CEREG: 1") != RT_NULL)
    rt_event_send(m5311_evt,NBMOUDLE_EVT_NET_REG);
}

static void urc_device_status_func(struct at_client *client, const char *data, rt_size_t size)
{
  int temp = 0;
  LOG_D("%s",data);
  sscanf(data,"+MLWEVTIND:%d",&temp);
  if(temp == 1)
    rt_event_send(m5311_evt,NBMOUDLE_EVT_REG_SUCCESS);
  else if(temp == 3)
    rt_event_send(m5311_evt,NBMOUDLE_EVT_UPDATE_SUCCESS);
  else if(temp == 5)
    rt_event_send(m5311_evt,NBMOUDLE_EVT_OBSERVE_SUCCESS);
}

static rt_err_t rt_m5311_init(struct rt_device *dev)
{
  rt_err_t result = RT_EOK;
  struct rt_nb_device *m5311;

  RT_ASSERT(dev != RT_NULL);
  m5311 = (struct rt_nb_device *)dev;
  
#if M5311_SAMPLE_POWER_PIN != -1
  rt_pin_mode(M5311_SAMPLE_POWER_PIN,PIN_MODE_OUTPUT);
  rt_pin_write(M5311_SAMPLE_POWER_PIN, PIN_LOW);
#endif

#if M5311_SAMPLE_RST_PIN != -1
  rt_pin_mode(M5311_SAMPLE_RST_PIN,PIN_MODE_OUTPUT);
  rt_pin_write(M5311_SAMPLE_RST_PIN, PIN_LOW);
#endif
    
#if M5311_SAMPLE_POWERON_PIN != -1
  rt_pin_mode(M5311_SAMPLE_POWERON_PIN,PIN_MODE_OUTPUT);
  rt_pin_write(M5311_SAMPLE_POWERON_PIN, PIN_HIGH);
#endif
  
#if M5311_SAMPLE_WAKEIN_PIN != -1
  rt_pin_mode(M5311_SAMPLE_WAKEIN_PIN,PIN_MODE_OUTPUT);
  rt_pin_write(M5311_SAMPLE_WAKEIN_PIN, PIN_HIGH);
#endif
  m5311->resp = at_create_resp(RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
  at_set_urc_table(m5311_urc_table, sizeof(m5311_urc_table) / sizeof(m5311_urc_table[0]));

  m5311_mt = rt_mutex_create("m5311", RT_IPC_FLAG_FIFO);
  m5311_evt = rt_event_create("m5311", RT_IPC_FLAG_FIFO);
  
  return result;
}

static rt_err_t rt_m5311_open(struct rt_device *dev, rt_uint16_t oflag)
{
  rt_err_t result = RT_EOK;
  struct rt_nb_device *m5311;

  RT_ASSERT(dev != RT_NULL);
  m5311 = (struct rt_nb_device *)dev;
  RT_ASSERT(m5311->resp != RT_NULL);

#if M5311_SAMPLE_POWER_PIN != -1
rt_pin_write(M5311_SAMPLE_POWER_PIN, PIN_HIGH);
#endif

  return result;
}

static rt_err_t rt_m5311_close(struct rt_device *dev)
{
  rt_err_t result = RT_EOK;
  struct rt_nb_device *m5311;

  RT_ASSERT(dev != RT_NULL);
  m5311 = (struct rt_nb_device *)dev;
  RT_ASSERT(m5311->resp != RT_NULL);

#if M5311_SAMPLE_POWER_PIN != -1
  rt_pin_write(M5311_SAMPLE_POWER_PIN, PIN_LOW);
#endif
  
  return result;
}

static rt_size_t rt_m5311_read(struct rt_device *dev,
                                rt_off_t          pos,
                                void             *buffer,
                                rt_size_t         size)
{
  struct rt_nb_device *m5311;

  RT_ASSERT(dev != RT_NULL);
  m5311 = (struct rt_nb_device *)dev;
  RT_ASSERT(m5311->resp != RT_NULL);

  if(m5311->nb_msg.len < size)
    size = m5311->nb_msg.len;
  
  rt_memcpy(buffer, m5311->nb_msg.dat, size);
  
  return size;
}

static rt_size_t rt_m5311_write(struct rt_device *dev,
                                 rt_off_t          pos,
                                 const void       *buffer,
                                 rt_size_t         size)
{
  NB_MSG msg;

  RT_ASSERT(dev != RT_NULL);

  msg.dat = (uint8_t *)buffer;
  msg.len = size;
  if(rt_device_control(dev, NBMODULE_SEND_DATA, &msg) == RT_EOK)
    return size;
  else
    return 0;
}
                                 
static rt_err_t rt_m5311_control(struct rt_device *dev,
                                  int              cmd,
                                  void             *args)
{
  rt_uint32_t evt = 0;
  struct rt_nb_device *m5311;

  RT_ASSERT(dev != RT_NULL);
  m5311 = (struct rt_nb_device *)dev;

  rt_mutex_take(m5311_mt, RT_WAITING_FOREVER);
  switch(cmd)
  {
    case NBMODULE_RST:
#if M5311_SAMPLE_RST_PIN != -1
  rt_pin_write(M5311_SAMPLE_RST_PIN, PIN_HIGH);
  rt_thread_mdelay(100);
  rt_pin_write(M5311_SAMPLE_RST_PIN, PIN_LOW);
#elif M5311_SAMPLE_POWER_PIN != -1
  rt_pin_write(M5311_SAMPLE_POWER_PIN, PIN_LOW);
  rt_thread_mdelay(100);
  rt_pin_write(M5311_SAMPLE_POWER_PIN, PIN_HIGH);
#endif
    m5311->info.net_status = 0;
    rt_event_recv(m5311_evt,0xffffffff,RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,RT_WAITING_NO,&evt); //��������¼�
      break;
    
    case NBMODULE_POWERON:
#if M5311_SAMPLE_POWERON_PIN != -1
  rt_pin_write(M5311_SAMPLE_POWERON_PIN, PIN_LOW);
  rt_thread_mdelay(1200);
  rt_pin_write(M5311_SAMPLE_POWERON_PIN, PIN_HIGH);
#endif
      break;
    
    case NBMODULE_QUERY_CSQ:               //��ѯ�ź�
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CSQ") != RT_EOK)
        goto error;
      if(at_resp_parse_line_args_by_kw(m5311->resp, "+CSQ:", "+CSQ:%u,",&m5311->info.csq) != 1)
        goto error;
      LOG_I("CSQ:%u",m5311->info.csq);
      if(args!= RT_NULL)
        *(uint8_t *)args = m5311->info.csq;
//      if(m5311->info.csq == 99)
//      if((*(rt_uint8_t*)args) == 99 || (*(rt_uint8_t*)args) < 8)
//        goto NBMODULE_CSQ_ERROR;
//        goto error;
      break;
      
    case NBMODULE_DISABLE_ECHO:             //ʧ�ܻ���
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "ATE%c",'0') != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_SET_ERROR:               //ʹ�ܱ���
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CMEE=1") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_EN_NET_REG_STATUS:       //ʹ������״̬�ϱ�
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CEREG=1") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
    
    case NBMODULE_QUERY_IMEI:              //��ѯIMEI
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CGSN=1") != RT_EOK)
        goto error;
      if(at_resp_parse_line_args_by_kw(m5311->resp, "+CGSN:", "+CGSN:%15s",m5311->info.imei) != 1)
        goto error;
      m5311->info.imei[sizeof(m5311->info.imei) - 1] = 0;
      if(args!= RT_NULL)
        rt_memcpy(args, m5311->info.imei, sizeof(m5311->info.imei));
      LOG_I("IMEI:%15s",m5311->info.imei);
      break;

    case NBMODULE_SET_BAND:                //����Ƶ�Σ��ƶ���ͨ8����5��
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
#ifndef RT_M5311_FULL_BAND
      if(at_exec_cmd(m5311->resp, "AT+CMBAND=%d", RT_M5311_BAND) != RT_EOK)
        goto error;
#else
      if(at_exec_cmd(m5311->resp, "AT+CMBAND=8,5,3") != RT_EOK)
        goto error;
#endif
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
/*********************************************************************
*	�������ã�����NBģ��PSM��������
*	��ڲ���:	mode					�Ƿ�����PSM
*						TAU_time			���������߻��Ѻ��ʱ��
*						acctive_time	���������ߵ�ʱ��
*	���ڲ���:	true					������ȷ
*	���ز���:	��
*	˵��:			Acctive_time			GPRS Timer 2
*						0 0 0 value is incremented in multiples of 2 seconds
*						0 0 1 value is incremented in multiples of 1 minute
*						0 1 0 value is incremented in multiples of decihours
*						1 1 1 value indicates that the timer is deactivated
*
*						TAU_time					GPRS Timer 3 
*						0 0 0 value is incremented in multiples of 10 minutes
*						0 0 1 value is incremented in multiples of 1 hour
*						0 1 0 value is incremented in multiples of 10 hours
*						0 1 1 value is incremented in multiples of 2 seconds
*						1 0 0 value is incremented in multiples of 30 seconds
*						1 0 1 value is incremented in multiples of 1 minute
*						1 1 0 value is incremented in multiples of 320 hours (NOTE)
*						1 1 1 value indicates that the timer is deactivated.
***********************************************************************/


    case NBMODULE_SET_PSM:                 //����PSMģʽ����
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_CPSMS_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CPSMS=%1s,,,\"%s\",\"%s\"", "1","00101000", "00100001") != RT_EOK)//	8hour	1min
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
/*****************************************************
*	�������ã�����NBģ��PTW��eDRXʱ�����
*	��ڲ���:	mode			�Ƿ�ʹ��eDRX
*						PTW_time	�����յ�ʱ��
*						eDRX_time	�����յ�ʱ����
*	���ڲ���:	��
*	���ز���:	��
*	˵��:				AcT-type
*									0								 not using eDRX
*									1					EC-GSM-IoT (A/Gb mode)
*									2								 GSM (A/Gb mode)
*									4						E-UTRAN (WB-S1 mode)
*									5						E-UTRAN (NB-S1 mode)
*
*							NB-S1mode 					PTW value
*								value			time(2.56 * (value + 1))
*								 0000												2.56
*
*							S1 mode 				eDRX value
*								value						 time
*								 0000					 	 5.12(Only WB-S1)
*								 0001						10.24(Only WB-S1)
*								 0010						20.48
*								 0011						40.96
*								 0100						61.44(Only WB-S1)
*								 0101						81.92
*								 0110						102.4(Only WB-S1)
*								 0111					 122.88(Only WB-S1)
*								 1000				 	 143.36(Only WB-S1)
*								 1001					 163.84
*								 1010					 327.68
*								 1011					 655.36
*								 1100					1310.72
*								 1101					2621.44
*								 1110					5242.88(Only NB-S1)
*								 1111				 10485.76(Only NB-S1)
*******************************************************/
    case NBMODULE_SET_EDRX:                //����eDRXģʽ����
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_NPTWEDRXS_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT*EDRXCFG=%1s,5,\"%s\",\"%s\"", "1", "0010", "0111") != RT_EOK)//20.48,20.48
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_QUERY_PDP_ADRR:          //��ѯPDP��ַ
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CGPADDR") != RT_EOK)
        goto error;
      if(at_resp_parse_line_args_by_kw(m5311->resp, "+CGPADDR:", "+CGPADDR:%*d,%15s",m5311->info.ip) != 1)
        goto error;
      m5311->info.ip[sizeof(m5311->info.ip) - 1] = 0;
      if(args != RT_NULL)
        goto error;
      LOG_I("IP:%s",m5311->info.ip);
      break;
    
    case NBMODULE_CREATE_DEVICE:          //�����豸
      if(rt_event_recv(m5311_evt,NBMOUDLE_EVT_NET_REG,RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,3000,&evt) != RT_EOK) //�ȴ�����ע��ɹ�
        goto error;
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+MLWNEW=%s,%d", RT_M5311_IP_ADDR, RT_M5311_PORT_ADDR) != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_REG_DEVICE:             //ע���豸
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+MLWOPEN=0,0") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      if(rt_event_recv(m5311_evt,NBMOUDLE_EVT_REG_SUCCESS|NBMOUDLE_EVT_OBSERVE_SUCCESS,RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR,5000,&evt) != RT_EOK)  //�ȴ��豸ע�ἰ���ĳɹ�
        goto error;
      break;
      
    case NBMODULE_UPDATE_DEVICE_STATUS:   //���������豸״̬
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+MLWUPDATE") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      if(rt_event_recv(m5311_evt,NBMOUDLE_EVT_UPDATE_SUCCESS,RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR,1000,&evt) != RT_EOK)  //�ȴ��豸���³ɹ�
        goto error;
      break;
      
    case NBMODULE_DEVICE_MSG_CONFIG:    //������Ϣ��ʽ
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+MLWCFG=0,0") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      m5311->info.net_status = 1;
      break;
      
    case NBMODULE_QUERY_CARD_ID:           //��ѯsim��id
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+ICCID") != RT_EOK)
        goto error;
      if(at_resp_parse_line_args_by_kw(m5311->resp, "+ICCID:", "+ICCID:%20s",m5311->info.iccid) != 1)
        goto error;
      m5311->info.iccid[sizeof(m5311->info.iccid) - 1] = 0;
      if(args!= RT_NULL)
        rt_memcpy(args, m5311->info.iccid, sizeof(m5311->info.iccid));
      LOG_I("ICCID:%20s",m5311->info.iccid);
      break;
    
    case NBMODULE_QUERY_IMSI:              //��ѯ�����ƶ��û�ʶ����
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CIMI") != RT_EOK)
        goto error;
      if(at_resp_parse_line_args(m5311->resp, 2, "%15s", m5311->info.imsi) != 1)
        goto error;
      m5311->info.imsi[sizeof(m5311->info.imsi) - 1] = 0;
      if(args!= RT_NULL)
        rt_memcpy(args, m5311->info.imsi, sizeof(m5311->info.imsi));
      LOG_I("IMSI:%15s",m5311->info.imsi);
      break;
    
    case NBMODULE_QUERY_TIME:              //��ѯ��ǰʱ��
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CCLK?") != RT_EOK)
        goto error;
#ifdef RT_USING_RTC
      rt_uint32_t year, month, day, hour, minute, second, zone;
      if(at_resp_parse_line_args_by_kw(m5311->resp, "+CCLK:", "+CCLK: %d/%d/%d,%d:%d:%d+%d", &year, &month, &day, &hour, &minute, &second, &zone) == 7)
      {
        hour = (hour + zone) % 24;
        year += 2000;
        day += zone / 24;
//        set_date(year, month, day);
//        set_time(hour, minute, second);
        LOG_I("TIME:%d/%d/%d,%d:%d:%d", year, month, day, hour, minute, second);
      }
#endif
      if(args!= RT_NULL && at_resp_parse_line_args_by_kw(m5311->resp, "+CCLK:", "+CCLK:%s", args) != 1)
        goto error;
      
      break;
    
    case NBMODULE_EN_SIGN_STATUS_REBACK:   //ʹ���ź�����״̬��������
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+CSCON=1") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_EN_SLEEP_INDICATION:    //ʹ�������˯��ָʾ
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT*SLEEP=1") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_EN_WAKEUP_INDICATION:   //ʹ�ܴ����˯�߻���ָʾ
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT*MATWAKEUP=1") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_EN_SLEEP:               //����ʹ��˯��
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT+SM=UNLOCK_FOREVER") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_ENTER_SLEEP:               //�������˯��
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_DEFAULT_TIMEOUT);
      if(at_exec_cmd(m5311->resp, "AT*ENTERSLEEP") != RT_EOK)
        goto error;
      if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
        goto error;
      break;
      
    case NBMODULE_WAKEUP:               //�������˯��
#if M5311_SAMPLE_WAKEIN_PIN != -1
      rt_pin_write(M5311_SAMPLE_WAKEIN_PIN, PIN_LOW);
      rt_thread_mdelay(60);
      rt_pin_write(M5311_SAMPLE_WAKEIN_PIN, PIN_HIGH);
      rt_thread_mdelay(150);
#elif M5311_SAMPLE_POWERON_PIN != -1
      rt_pin_write(M5311_SAMPLE_POWERON_PIN, PIN_LOW);
      rt_thread_mdelay(90);
      rt_pin_write(M5311_SAMPLE_POWERON_PIN, PIN_HIGH);
      rt_thread_mdelay(180);
#endif
      break;

    case NBMODULE_SEND_DATA:               //��������
      at_resp_set_info(m5311->resp, RT_M5311_RESP_SIZE, 0, NBMODULE_SEND_DATA_TIMEOUT);
      RT_ASSERT(args != RT_NULL);
      NB_MSG *msg = (NB_MSG *)args;
      uint8_t *dat = rt_malloc(2 * msg->len);
      if(dat != RT_NULL)
      {
        hextostring(dat, msg->dat, msg->len);
        if(at_exec_cmd(m5311->resp, "AT+MLWSEND=%d,%s", msg->len, dat) != RT_EOK)
        {
          rt_free(dat);
          goto error;
        }
        rt_free(dat);
        if(at_resp_get_line_by_kw(m5311->resp, "OK") == RT_NULL)
          goto error;
      }
      else
        goto error;
      break;
    
    case NBMODULE_QUERY_NET_STATUS:         //��ѯ����״̬
      if(m5311->info.net_status != 1)
      {
        rt_mutex_release(m5311_mt);
        return NBMODULE_NO_NET;
      }
      break;
    
    default:
      break;
  }
  rt_mutex_release(m5311_mt);
  return NBMODULE_EOK;
  
error:
  {
    rt_uint32_t error = 0;
    rt_mutex_release(m5311_mt);
    if(at_resp_parse_line_args_by_kw(m5311->resp, "+CME ERROR: ", "+CME ERROR: %d", &error) == 1)
    {
      LOG_E("+CME ERROR: %u", error);
    }
    return NBMODULE_ERROR;
  }
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops m5311_ops = 
{
  rt_m5311_init,
  rt_m5311_open,
  rt_m5311_close,
  rt_m5311_read,
  rt_m5311_write,
  rt_m5311_control
};
#endif
rt_err_t m5311_device_register(struct rt_nb_device *m5311,
                                const char              *name,
                                rt_uint32_t              flag,
                                void                    *data)
{
  rt_err_t ret;
  struct rt_device *device;
  RT_ASSERT(m5311 != RT_NULL);

  device = &(m5311->parent);

  device->type        = RT_Device_Class_Char;
  device->rx_indicate = RT_NULL;
  device->tx_complete = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
  device->ops         = &serial_ops;
#else
  device->init        = rt_m5311_init;
  device->open        = rt_m5311_open;
  device->close       = rt_m5311_close;
  device->read        = rt_m5311_read;
  device->write       = rt_m5311_write;
  device->control     = rt_m5311_control;
#endif
  device->user_data   = data;

  /* register a character device */
  ret = rt_device_register(device, name, flag);
  
  return ret;
}

int m5311_device_init(void)
{
  if(at_client_init(RT_M5311_DEVICE,2048) != RT_EOK)
    return RT_ERROR;
  
  if(m5311_device_register(&m5311, "m5311", RT_DEVICE_FLAG_RDWR, RT_NULL) != RT_EOK)
    return RT_ERROR;
  else
    return RT_EOK;
}
INIT_COMPONENT_EXPORT(m5311_device_init);

#endif /* BSP_USING_M5311 */
